﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using WQDSkin.Forms.ValueBoxes;

namespace WQDSkin.Forms.Controls
{
    [DefaultEvent("Checked")]
    public class WQDToggleButton : ButtonBase
    {
        static WQDToggleButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ToggleButton), new FrameworkPropertyMetadata(typeof(WQDToggleButton))); 
        }
 
        public WQDToggleButton() : base()
        {
        }

 
        public static readonly RoutedEvent CheckedEvent = EventManager.RegisterRoutedEvent("Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(WQDToggleButton));
 
        public static readonly RoutedEvent UncheckedEvent = EventManager.RegisterRoutedEvent("Unchecked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(WQDToggleButton));
 
        public static readonly RoutedEvent IndeterminateEvent = EventManager.RegisterRoutedEvent("Indeterminate", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(WQDToggleButton));

        //[Category("Behavior")]
        //public event RoutedEventHandler Checked;
 
        //[Category("Behavior")]
        //public event RoutedEventHandler Unchecked;
 
        //[Category("Behavior")]
        //public event RoutedEventHandler Indeterminate;
         
        public static readonly DependencyProperty IsCheckedProperty =
               DependencyProperty.Register(
                       "IsChecked",
                       typeof(bool?),
                       typeof(ToggleButton),
                       new FrameworkPropertyMetadata(
                               BooleanBoxes.FalseBox,
                               FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                               new PropertyChangedCallback(OnIsCheckedChanged)));

        [Category("Appearance")]
        [TypeConverter(typeof(NullableBoolConverter))]
        [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
        public bool? IsChecked
        {
            get
            {
                // Because Nullable<bool> unboxing is very slow (uses reflection) first we cast to bool
                object value = GetValue(IsCheckedProperty);
                if (value == null)
                    return new Nullable<bool>();
                else
                    return new Nullable<bool>((bool)value);
            }
            set
            {
                SetValue(IsCheckedProperty, value.HasValue ? BooleanBoxes.Box(value.Value) : null);
            }
        }

        private static object OnGetIsChecked(DependencyObject d) { return ((ToggleButton)d).IsChecked; }

        private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WQDToggleButton button = (WQDToggleButton)d;
            bool? oldValue = (bool?)e.OldValue;
            bool? newValue = (bool?)e.NewValue;

            //doing soft casting here because the peer can be that of RadioButton and it is not derived from
            //ToggleButtonAutomationPeer - specifically to avoid implementing TogglePattern
            WQDToggleButtonAutomationPeer peer = UIElementAutomationPeer.FromElement(button) as WQDToggleButtonAutomationPeer;
            if (peer != null)
            {
                peer.RaiseToggleStatePropertyChangedEvent(oldValue, newValue);
            }

            if (newValue == true)
            {
                button.OnChecked(new RoutedEventArgs(CheckedEvent));
            }
            else if (newValue == false)
            {
                button.OnUnchecked(new RoutedEventArgs(UncheckedEvent));
            }
            else
            {
                button.OnIndeterminate(new RoutedEventArgs(IndeterminateEvent));
            }

            button.UpdateVisualState();
        }

        protected virtual void OnChecked(RoutedEventArgs e)
        {
            RaiseEvent(e);
        }

        protected virtual void OnUnchecked(RoutedEventArgs e)
        {
            RaiseEvent(e);
        }
         
        protected virtual void OnIndeterminate(RoutedEventArgs e)
        {
            RaiseEvent(e);
        }

        public static readonly DependencyProperty IsThreeStateProperty =
               DependencyProperty.Register(
                       "IsThreeState",
                       typeof(bool),
                       typeof(WQDToggleButton),
                       new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
 
        [Bindable(true), Category("Behavior")]
        public bool IsThreeState
        {
            get { return (bool)GetValue(IsThreeStateProperty); }
            set { SetValue(IsThreeStateProperty, BooleanBoxes.Box(value)); }
        }
         
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new WQDToggleButtonAutomationPeer(this);
        }
         
        protected override void OnClick()
        {
            OnToggle();
            base.OnClick();
        }

        

        protected internal virtual void OnToggle()
        {
            // If IsChecked == true && IsThreeState == true   --->  IsChecked = null
            // If IsChecked == true && IsThreeState == false  --->  IsChecked = false
            // If IsChecked == false                          --->  IsChecked = true
            // If IsChecked == null                           --->  IsChecked = false
            bool? isChecked;
            if (IsChecked == true)
                isChecked = IsThreeState ? (bool?)null : (bool?)false;
            else // false or null
                isChecked = IsChecked.HasValue; // HasValue returns true if IsChecked==false
            this.SetCurrentValue(IsCheckedProperty, isChecked);
        }


        internal void UpdateVisualState()
        {
            UpdateVisualState(true);
        }

        internal void UpdateVisualState(bool useTransitions)
        { 
                ChangeVisualState(useTransitions);  
        }

        internal virtual void ChangeVisualState(bool useTransitions)
        {
            ChangeValidationVisualState(useTransitions);
        }

        internal void ChangeValidationVisualState(bool useTransitions)
        {
            if (Validation.GetHasError(this))
            {
                if (IsKeyboardFocused)
                {
                    VisualStateManager.GoToState(this, VisualStates.StateInvalidFocused, useTransitions);
                }
                else
                {
                    VisualStateManager.GoToState(this, VisualStates.StateInvalidUnfocused, useTransitions);
                }
            }
            else
            {
                VisualStateManager.GoToState(this, VisualStates.StateValid, useTransitions);
            }
        }

    }
}
